package com.mdnote.practice.dp;

/**
 * @author Rhythm-2019
 * @version 1.0
 * @date 2020/10/11
 * @description 分割等和子集
 */
public class LeetCode426 {

    public static void main(String[] args) {
        LeetCode426 leetCode426 = new LeetCode426();
        boolean b = leetCode426.canPartitionPlus(new int[]{2, 3, 5});

        System.out.println(b);
    }

    /**
     * DP实现，转换为01背包问题
     * 1. 状态：当前处理的数字I，当前子集的和J
     * 2. 定义DP数组  dp[i][j] 是否能够成为等和子集， i 当前需要处理的数字 j 当前序列总和
     */
    public boolean canPartition(int[] nums) {

        if (nums.length <= 2) {
            return false;
        }

        int sum = 0, maxValue = 0;
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] > maxValue) {
                maxValue = nums[i];
            }
            sum += nums[i];
        }

        if (sum % 2 == 1) {
            return false;
        }
        int target = sum / 2;
        if (maxValue > target) {
            return false;
        }

        boolean[][] dp = new boolean[nums.length + 1][target + 1];

        // base case
        for (int i = 0; i < dp.length; i++) {
            dp[i][0] = true;
        }


        for (int i = 1; i < dp.length; i++) {
            for (int j = 1; j < dp[i].length; j++) {
                if (j - nums[i - 1] >= 0) {
                    dp[i][j] = dp[i - 1][j] || dp[i - 1][j - nums[i - 1]];
                } else {
                    dp[i][j] = dp[i - 1][j];
                }
            }
        }
        return dp[nums.length][target];
    }

    public boolean canPartitionPlus(int[] nums) {

        if (nums.length <= 2) {
            return false;
        }

        int sum = 0, maxValue = 0;
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] > maxValue) {
                maxValue = nums[i];
            }
            sum += nums[i];
        }

        if (sum % 2 == 1) {
            return false;
        }
        int target = sum / 2;
        if (maxValue > target) {
            return false;
        }

        boolean[] dp = new boolean[target + 1];

        // base case
        dp[0] = true;

        for (int i = 0; i < nums.length; i++) {
            for (int j = target; j >= 0; j--) {
                if (j - nums[i] >= 0) {
                    dp[j] = dp[j] || dp[j - nums[i]];
                }
            }
        }
        return dp[target];
    }
}
